home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Freeware / Griffith 0.9.8 / griffith-0.9.8-win32.exe / {app} / lib / sql.py < prev    next >
Text File  |  2008-11-17  |  22KB  |  533 lines

  1. # -*- coding: UTF-8 -*-
  2.  
  3. __revision__ = '$Id: sql.py 1056 2008-11-16 23:29:08Z piotrek $'
  4.  
  5. # Copyright (c) 2005-2008 Vasco Nunes, Piotr O┼╝arowski
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU Library General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  20.  
  21. # You may use and distribute this software under the terms of the
  22. # GNU General Public License, version 2 or later
  23.  
  24. from sqlalchemy import *
  25. import os.path
  26. import gutils
  27. import gtk
  28.  
  29. class DBTable(object):#{{{
  30.     def __repr__(self):
  31.         return "%s:%s" % (self.__class__.__name__, self.name)
  32.     def add_to_db(self):
  33.         if self.name is None or len(self.name)==0:
  34.             debug.show("%s: name can't be empty" % self.__class__.__name__)
  35.             return False
  36.         # check if achannel already exists
  37.         if self.get_by(name=self.name) is not None:
  38.             debug.show("%s: '%s' already exists" % (self.__class__.__name__, self.name))
  39.             return False
  40.         debug.show("%s: adding '%s' to database..." % (self.__class__.__name__, self.name))
  41.         self.save()
  42.         try:
  43.             self.flush()
  44.         except exceptions.SQLError, e:
  45.             debug.show("%s: add_to_db: %s" % (self.__class__.__name__, e))
  46.             return False
  47.         self.refresh()
  48.         return True
  49.     def remove_from_db(self):
  50.         dbtable_id = self.__dict__[self.__class__.__name__.lower() + '_id']
  51.         if dbtable_id<1:
  52.             debug.show("%s: none selected => none removed" % self.__class__.__name__)
  53.             return False
  54.         tmp = None
  55.         if hasattr(self,'movies'):
  56.             tmp = getattr(self,'movies')
  57.         elif hasattr(self,'movielangs'):
  58.             tmp = getattr(self,'movielangs')
  59.         if tmp and len(tmp)>0:
  60.             gutils.warning(self, msg=_("This item is in use.\nOperation aborted!"))
  61.             return False
  62.         debug.show("%s: removing '%s' (id=%s) from database..."%(self.__class__.__name__, self.name, dbtable_id))
  63.         self.delete()
  64.         try:
  65.             self.flush()
  66.         except exceptions.SQLError, e:
  67.             debug.show("%s: remove_from_db: %s" % (self.__class__.__name__, e))
  68.             return False
  69.         #self.refresh()
  70.         return True
  71.     def update_in_db(self):
  72.         dbtable_id = self.__dict__[self.__class__.__name__.lower() + '_id']
  73.         if dbtable_id<1:
  74.             debug.show("%s: none selected => none updated" % self.__class__.__name__)
  75.             return False
  76.         if self.name is None or len(self.name)==0:
  77.             debug.show("%s: name can't be empty" % self.__class__.__name__)
  78.             return False
  79.         tmp = self.get_by(name=self.name)
  80.         if tmp is not None and tmp is not self:
  81.             gutils.warning(self, msg=_("This name is already in use!"))
  82.             return False
  83.         self.update()
  84.         try:
  85.             self.flush()
  86.         except exceptions.SQLError, e:
  87.             debug.show("%s: update_in_db: %s" % (self.__class__.__name__, e))
  88.             return False
  89.         self.refresh()
  90.         return True#}}}
  91.  
  92. class GriffithSQL:
  93.     version = 2    # database format version, incrase after any changes in data structures
  94.     metadata = None
  95.     class Configuration(object):
  96.         def __repr__(self):
  97.             return "Config:%s=%s" % (self.param, self.value)
  98.     class AChannel(DBTable):
  99.         pass
  100.     class ACodec(DBTable):
  101.         pass
  102.     class Collection(DBTable):
  103.         pass
  104.     class Lang(DBTable):
  105.         pass
  106.     class Medium(DBTable):
  107.         pass
  108.     class MovieLang(object):
  109.         def __repr__(self):
  110.             return "MovieLang:%s-%s (Type:%s ACodec:%s AChannel:%s SubFormat:%s)" % \
  111.                 (self.movie_id, self.lang_id, self.type, self.acodec_id, self.achannel_id, self.subformat_id)
  112.     class MovieTag(object):
  113.         def __repr__(self):
  114.             return "MovieTag:%s-%s" % (self.movie_id, self.tag_id)
  115.     class Person(DBTable):
  116.         pass
  117.     class SubFormat(DBTable):
  118.         pass
  119.     class Tag(DBTable):
  120.         def remove_from_db(self):
  121.             if len(self.movietags) > 0:
  122.                 gutils.warning(self, msg=_("This item is in use.\nOperation aborted!"))
  123.                 return False
  124.             return DBTable.remove_from_db(self)
  125.     class VCodec(DBTable):
  126.         pass
  127.     class Volume(DBTable):
  128.         pass
  129.     class Loan(object):#{{{
  130.         def __repr__(self):
  131.             return "Loan:%s (movie:%s person:%s)" % (self.loan_id, self.movie_id, self.person_id)
  132.         def __setitem__(self, key, value):
  133.             if key == 'movie_id' and value:
  134.                 if GriffithSQL.Movie.get_by(movie_id=value) is None:
  135.                     raise ValueError('wrong movie_id')
  136.             elif key == 'person_id' and value:
  137.                 if GriffithSQL.Person.get_by(person_id=value) is None:
  138.                     raise ValueError('wrong movie_id')
  139.             self[key] = value
  140.         def _validate(self):
  141.             if self.movie_id is None:
  142.                 raise ValueError('movie_id is not set')
  143.             if self.person_id is None:
  144.                 raise ValueError('person_id is not set')
  145.             if self.movie is None:
  146.                 self.movie = GriffithSQL.Movie.get_by(movie_id=self.movie_id)
  147.                 if self.movie is None:
  148.                     raise ValueError('wrong movie_id')
  149.             if self.person is None:
  150.                 self.person = GriffithSQL.Person.get_by(person_id=self.person_id)
  151.                 if self.person is None:
  152.                     raise ValueError('wrong person_id')
  153.             if self.collection_id>0 and self.collection is None:
  154.                 self.collection = GriffithSQL.Collection.get_by(collection_id=self.collection_id)
  155.                 if self.collection is None:
  156.                     raise ValueError('wrong collection_id')
  157.             if self.volume_id>0 and self.volume is None:
  158.                 self.volume = GriffithSQL.Volume.get_by(volume_id=self.volume_id)
  159.                 if self.volume is None:
  160.                     raise ValueError('wrong volume_id')
  161.             return True
  162.         def set_loaned(self):
  163.             """
  164.             Set loaned=True for all movies in volume/collection and for movie itself
  165.             Set loan's date to today's date
  166.             """
  167.             self._validate()
  168.  
  169.             if self.collection is not None:
  170.                 self.movie.mapper.mapped_table.update(self.movie.c.collection_id==self.collection_id).execute(loaned=True)
  171.                 self.collection.loaned = True
  172.                 self.collection.update()
  173.             if self.volume is not None:
  174.                 self.movie.mapper.mapped_table.update(self.movie.c.volume_id==self.volume_id).execute(loaned=True)
  175.                 self.volume.loaned = True
  176.                 self.volume.update()
  177.             if self.movie is None:
  178.                 self.movie = Movie.get_by(movie_id=self.movie_id)
  179.             self.movie.loaned = True
  180.             self.movie.update()
  181.             if self.date is None:
  182.                 self.date = func.current_date()    # update loan date
  183.             self.return_date = None
  184.             self.save_or_update()
  185.             try:
  186.                 self.mapper.get_session().flush()
  187.                 self.refresh()
  188.             except exceptions.SQLError, e:
  189.                 debug.show("set_loaned: %s" % e)
  190.                 return False
  191.             return True
  192.         def set_returned(self):
  193.             """
  194.             Set loaned=False for all movies in volume/collection and for movie itself.
  195.             Set return_date to today's date
  196.             """
  197.             self._validate()
  198.             if self.collection is not None:
  199.                 self.movie.mapper.mapped_table.update(self.movie.c.collection_id==self.collection_id).execute(loaned=False)
  200.                 self.collection.loaned = False
  201.                 self.collection.update()
  202.             if self.volume_id is not None:
  203.                 self.movie.mapper.mapped_table.update(self.movie.c.volume_id==self.volume_id).execute(loaned=False)
  204.                 self.volume.loaned = False
  205.                 self.volume.update()
  206.             self.movie.loaned = False
  207.             self.movie.update()
  208.             if self.return_date is None:
  209.                 self.return_date = func.current_date()
  210.             self.save_or_update()
  211.             try:
  212.                 self.mapper.get_session().flush()
  213.                 self.refresh()
  214.             except exceptions.SQLError, e:
  215.                 debug.show("set_returned: %s" % e)
  216.                 return False
  217.             return True
  218.             #}}}
  219.     class Movie(object):#{{{
  220.         def __repr__(self):
  221.             return "Movie:%s (number=%s)" % (self.movie_id, self.number)
  222.         def __setitem__(self, key, value):
  223.             setattr(self,key,value)
  224.         def __getitem__(self, key):
  225.             return getattr(self,key)
  226.         def has_key(self, key):
  227.             if key in ('volume','collection','medium','vcodec','loans','tags','languages','lectors','dubbings','subtitles'):
  228.                 return True
  229.             else:
  230.                 return self.c.has_key(key)
  231.         def remove_from_db(self):
  232.             if self.loaned == True:
  233.                 debug.show("You can't remove loaned movie!")
  234.                 return False
  235.             self.delete()
  236.             try:
  237.                 self.flush()
  238.             except exceptions.SQLError, e:
  239.                 debug.show("remove_from_db: %s" % e)
  240.                 return False
  241.             return True
  242.         def update_in_db(self, t_movies=None):
  243.             if self.movie_id < 1:
  244.                 raise ValueError('movie_id is not set')
  245.             if t_movies is not None:
  246.                 self.languages.clear()
  247.                 self.tags.clear()
  248.                 #self.mapper.mapped_table.update(self.c.movie_id==t_movies['movie_id']).execute(t_movies)
  249.             return self.add_to_db(t_movies)
  250.         def add_to_db(self, t_movies=None):
  251.             if t_movies is not None:
  252.                 t_tags = t_languages = None
  253.                 if t_movies.has_key('tags'):
  254.                     t_tags = t_movies.pop('tags')
  255.                 if t_movies.has_key('languages'):
  256.                     t_languages = t_movies.pop('languages')
  257.                 for i in self.c.keys():
  258.                     if t_movies.has_key(i):
  259.                         self[i] = t_movies[i]
  260.                 # languages
  261.                 if t_languages is not None:
  262.                     for lang in t_languages:
  263.                         if lang[0]>0:
  264.                             ml = GriffithSQL.MovieLang(lang_id=lang[0], type=lang[1],
  265.                                 acodec_id=lang[2], achannel_id=lang[3], subformat_id=lang[4])
  266.                             self.languages.append(ml)
  267.                 # tags
  268.                 if t_tags is not None:
  269.                     for tag in t_tags.keys():
  270.                         self.tags.append(GriffithSQL.Tag(tag_id=tag))
  271.             self.update()
  272.             try:
  273.                 self.flush()
  274.             except exceptions.SQLError, e:
  275.                 debug.show("add_to_db: %s" % e)
  276.                 if e.args[0][:16] == '(IntegrityError)':
  277.                     gutils.error(None, _('Column "%s" is not unique') % _('Number'))
  278.                 return False
  279.             self.refresh()
  280.             return True
  281.         #}}}
  282.  
  283.     def __init__(self, config, gdebug, griffith_dir):
  284.         from sqlalchemy.mods.threadlocal import assign_mapper
  285.         from sqlalchemy.exceptions import InvalidRequestError
  286.         global debug
  287.         debug = gdebug
  288.         if config.get('type', None, section='database') is None:
  289.             config.set('type', 'sqlite', section='database')
  290.  
  291.         if config.get('type', 'sqlite', section='database') != 'sqlite':
  292.             if config.get('host', None, section='database') is None:
  293.                 config.set('host', '127.0.0.1', section='database')
  294.             if config.get('user', None, section='database') is None:
  295.                 config.set('user', 'griffith', section='database')
  296.             if config.get('passwd', None, section='database') is None:
  297.                 config.set('passwd', 'gRiFiTh', section='database')
  298.             if config.get('name', None, section='database') is None:
  299.                 config.set('name', 'griffith', section='database')
  300.  
  301.         # connect to database --------------------------------------{{{
  302.         if config.get('type', section='database') == 'sqlite':
  303.             url = "sqlite:///%s" % os.path.join(griffith_dir, config.get('name', 'griffith', section='database') + '.db')
  304.         elif config.get('type', section='database') == 'postgres':
  305.             if config.get('port', 0, section='database')==0:
  306.                 config.set('port', 5432, section='database')
  307.             url = "postgres://%s:%s@%s:%d/%s" % (
  308.                 config.get('user', section='database'),
  309.                 config.get('passwd', section='database'),
  310.                 config.get('host', section='database'),
  311.                 int(config.get('port', section='database')),
  312.                 config.get('name', section='database'))
  313.         elif config.get('type', section='database') == 'mysql':
  314.             if config.get('port', 0, section='database')==0:
  315.                 config.set('port', 3306, section='database')
  316.             url = "mysql://%s:%s@%s:%d/%s" % (
  317.                 config.get('user', section='database'),
  318.                 config.get('passwd', section='database'),
  319.                 config.get('host', section='database'),
  320.                 int(config.get('port', section='database')),
  321.                 config.get('name', section='database'))
  322.         elif config.get('type', section='database') == 'mssql':
  323.             if config.get('port', 0, section='database')==0:
  324.                 config.set('port', 1433, section='database')
  325.             # use_scope_identity=0 have to be set as workaround for a sqlalchemy bug
  326.             # but it is not guaranteed that the right identity value will be selected
  327.             # because the select @@identity statement selects the very last id which
  328.             # also can be a id from a trigger-insert or another user
  329.             # sqlalchemy uses a wrong syntax. It has to select the id within the insert
  330.             # statement: insert <table> (<columns>) values (<values>) select scope_identity()
  331.             # (one statement !) After preparing and executing there should be a fetch
  332.             # If it is executed as two separate statements the scope is lost after insert.
  333.             url = "mssql://%s:%s@%s:%d/%s?use_scope_identity=0" % (
  334.                 config.get('user', section='database'),
  335.                 config.get('passwd', section='database'),
  336.                 config.get('host', section='database'),
  337.                 int(config.get('port', section='database')),
  338.                 config.get('name', section='database'))
  339.         else:
  340.             config.set('type', 'sqlite', section='database')
  341.             url = "sqlite:///%s" % os.path.join(griffith_dir, config.get('name', 'griffith', section='database') + '.db')
  342.         try:
  343.             self.metadata = BoundMetaData(url)
  344.         except Exception, e:    # InvalidRequestError, ImportError
  345.             debug.show("BoundMetaData: %s" % e)
  346.             config.set('type', 'sqlite', section='database')
  347.             gutils.warning(self, "%s\n\n%s" % (_('Cannot connect to database.\nFalling back to SQLite.'), _('Please check debug output for more informations.')))
  348.             self.metadata = BoundMetaData("sqlite:///%s" % os.path.join(griffith_dir, config.get('name', 'griffith', section='database') + '.db'))
  349.  
  350.         # try to establish a db connection
  351.         try:
  352.             self.metadata.engine.connect()
  353.         except Exception, e:
  354.             debug.show("engine connection: %s" % e)
  355.             gutils.error(self, _('Database connection failed.'))
  356.             config.set('type', 'sqlite', section='database')
  357.             url = "sqlite:///%s" % os.path.join(griffith_dir, 'griffith.db')
  358.             self.metadata = BoundMetaData(url)
  359.             self.metadata.engine.connect()
  360.         #}}}
  361.  
  362.         # prepare tables interface ---------------------------------{{{
  363.         movies = Table('movies', self.metadata,
  364.             Column('movie_id', Integer, primary_key = True),
  365.             Column('number', Integer, nullable=False, unique=True),
  366.             Column('collection_id', Integer, ForeignKey('collections.collection_id')),
  367.             Column('volume_id', Integer, ForeignKey('volumes.volume_id')),
  368.             Column('medium_id', Integer, ForeignKey('media.medium_id')),
  369.             Column('vcodec_id', Integer, ForeignKey('vcodecs.vcodec_id')),
  370.             Column('loaned', Boolean, nullable=False, default=False),
  371.             Column('seen', Boolean, nullable=False, default=False),
  372.             Column('rating', Smallinteger(2)),
  373.             Column('color', Smallinteger),
  374.             Column('cond', Smallinteger),    # MySQL will not accept name "condition"
  375.             Column('layers', Smallinteger),
  376.             Column('region', Smallinteger),
  377.             Column('media_num', Smallinteger),
  378.             Column('runtime', Integer),
  379.             Column('year', Integer),
  380.             Column('o_title', VARCHAR(255)),
  381.             Column('title', VARCHAR(255)),
  382.             Column('director', VARCHAR(255)),
  383.             Column('o_site', VARCHAR(255)),
  384.             Column('site', VARCHAR(255)),
  385.             Column('trailer', VARCHAR(256)),
  386.             Column('country', VARCHAR(128)),
  387.             Column('genre', VARCHAR(128)),
  388.             Column('image', VARCHAR(128)),
  389.             Column('studio', VARCHAR(128)),
  390.             Column('classification', VARCHAR(128)),
  391.             Column('cast', TEXT),
  392.             Column('plot', TEXT),
  393.             Column('notes', TEXT))
  394.         loans = Table('loans', self.metadata,
  395.             Column('loan_id', Integer, primary_key=True),
  396.             Column('person_id', Integer, ForeignKey('people.person_id'), nullable=False),
  397.             Column('movie_id', Integer, ForeignKey('movies.movie_id'), nullable=False),
  398.             Column('volume_id', Integer, ForeignKey('volumes.volume_id')),
  399.             Column('collection_id', Integer, ForeignKey('collections.collection_id')),
  400.             Column('date', Date, nullable=False, default=func.current_date()),
  401.             Column('return_date', Date, nullable=True))
  402.         people = Table('people', self.metadata,
  403.             Column('person_id', Integer, primary_key=True),
  404.             Column('name', VARCHAR(255), nullable=False, unique=True),
  405.             Column('email', VARCHAR(128)),
  406.             Column('phone', VARCHAR(64)))
  407.         volumes = Table('volumes', self.metadata,
  408.             Column('volume_id', Integer, primary_key=True),
  409.             Column('name', VARCHAR(64), nullable=False, unique=True),
  410.             Column('loaned', Boolean, nullable=False, default=False))
  411.         collections = Table('collections', self.metadata,
  412.             Column('collection_id', Integer, primary_key=True),
  413.             Column('name', VARCHAR(64), nullable=False, unique=True),
  414.             Column('loaned', Boolean, nullable=False, default=False))
  415.         media = Table('media', self.metadata,
  416.             Column('medium_id', Integer, primary_key=True),
  417.             Column('name', VARCHAR(64), nullable=False, unique=True))
  418.         languages = Table('languages', self.metadata,
  419.             Column('lang_id', Integer, primary_key=True),
  420.             Column('name', VARCHAR(64), nullable=False, unique=True))
  421.         vcodecs = Table('vcodecs', self.metadata,
  422.             Column('vcodec_id', Integer, primary_key=True),
  423.             Column('name', VARCHAR(64), nullable=False, unique=True))
  424.         acodecs = Table('acodecs', self.metadata,
  425.             Column('acodec_id', Integer, primary_key=True),
  426.             Column('name', VARCHAR(64), nullable=False, unique=True))
  427.         achannels = Table('achannels', self.metadata,
  428.             Column('achannel_id', Integer, primary_key=True),
  429.             Column('name', VARCHAR(64), nullable=False, unique=True))
  430.         subformats = Table('subformats', self.metadata,
  431.             Column('subformat_id', Integer, primary_key=True),
  432.             Column('name', VARCHAR(64), nullable=False, unique=True))
  433.         tags = Table('tags', self.metadata,
  434.             Column('tag_id', Integer, primary_key=True),
  435.             Column('name', VARCHAR(64), nullable=False, unique=True))
  436.         movie_lang = Table('movie_lang', self.metadata,
  437.             Column('ml_id', Integer, primary_key=True),
  438.             Column('type', Smallinteger), # 0: Original, 1:lector, 2:dubbing, 3:subtitle 
  439.             Column('movie_id', Integer, ForeignKey('movies.movie_id'), nullable=False),
  440.             Column('lang_id', Integer, ForeignKey('languages.lang_id'), nullable=False),
  441.             Column('acodec_id', Integer, ForeignKey('acodecs.acodec_id')),
  442.             Column('achannel_id', Integer, ForeignKey('achannels.achannel_id')),
  443.             Column('subformat_id', Integer, ForeignKey('subformats.subformat_id')))
  444.         movie_tag = Table('movie_tag', self.metadata,
  445.             Column('mt_id', Integer, primary_key=True),
  446.             Column('movie_id', Integer, ForeignKey('movies.movie_id')),
  447.             Column('tag_id', Integer, ForeignKey('tags.tag_id')))
  448.         configuration = Table('configuration', self.metadata,
  449.             Column('param', VARCHAR(16), primary_key=True),
  450.             Column('value', VARCHAR(128), nullable=False))#}}}
  451.  
  452.         # mappers -------------------------------------------------#{{{
  453.         assign_mapper(self.Configuration, configuration)
  454.         assign_mapper(self.Volume,volumes, properties={
  455.             'movies': relation(self.Movie, backref='volume')})
  456.         assign_mapper(self.Collection, collections, properties={
  457.             'movies': relation(self.Movie, backref='collection')})
  458.         assign_mapper(self.Medium, media, properties={
  459.             'movies': relation(self.Movie, backref='medium')})
  460.         assign_mapper(self.VCodec, vcodecs, properties={
  461.             'movies': relation(self.Movie, backref='vcodec')})
  462.         assign_mapper(self.Person, people, properties = {
  463.             'loans'    : relation(self.Loan, backref='person', cascade='all, delete-orphan')})
  464.         assign_mapper(self.MovieLang, movie_lang, primary_key=[movie_lang.c.ml_id], properties = {
  465.             'movie'    : relation(self.Movie, lazy=False),
  466.             'language' : relation(self.Lang, lazy=False),
  467.             'achannel' : relation(self.AChannel),
  468.             'acodec'   : relation(self.ACodec),
  469.             'subformat': relation(self.SubFormat)})
  470.         assign_mapper(self.ACodec, acodecs, properties={
  471.             'movielangs': relation(self.MovieLang, lazy=False)})
  472.         assign_mapper(self.AChannel, achannels, properties={
  473.             'movielangs': relation(self.MovieLang, lazy=False)})
  474.         assign_mapper(self.SubFormat, subformats, properties={
  475.             'movielangs': relation(self.MovieLang, lazy=False)})
  476.         assign_mapper(self.Lang, languages, properties={
  477.             'movielangs': relation(self.MovieLang, lazy=False)})
  478.         assign_mapper(self.MovieTag, movie_tag)
  479.         assign_mapper(self.Tag, tags, properties={'movietags': relation(self.MovieTag, backref='tag')})
  480.         assign_mapper(self.Loan, loans, properties = {
  481.             'volume'    : relation(self.Volume),
  482.             'collection': relation(self.Collection)})
  483.         assign_mapper(self.Movie, movies, order_by=movies.c.number , properties = {
  484.             'loans'     : relation(self.Loan, backref='movie', cascade='all, delete-orphan'),
  485.             #'tags'       : relation(self.Tag, cascade='all, delete-orphan', secondary=movie_tag,
  486.             'tags'      : relation(self.Tag, secondary=movie_tag,
  487.                     primaryjoin=movies.c.movie_id==movie_tag.c.movie_id,
  488.                     secondaryjoin=movie_tag.c.tag_id==tags.c.tag_id),
  489.             'languages' : relation(self.MovieLang, cascade='all, delete-orphan')})#}}}
  490.         
  491.         # check if database needs upgrade
  492.         try:
  493.             v = self.Configuration.get_by(param='version')    # returns None if table exists && param ISNULL
  494.         except exceptions.SQLError, e:    # table doesn't exist
  495.             debug.show("DB version: %s" % e)
  496.             v = 0
  497.  
  498.         if v is not None and v > 1:
  499.             v = int(v.value)
  500.         if v < self.version:
  501.             from dbupgrade import upgrade_database
  502.             if not upgrade_database(self, v):
  503.                 raise Exception("cannot upgrade database")
  504.         elif v > self.version:
  505.             debug.show("database version mismatch (detacted:%s; current:%s)" % (v, self.version))
  506.             gutils.warning(self, _('This database requires newer version of Griffith.'))
  507.             raise Exception("database version mismatch")
  508.  
  509. # for debugging (run: ipython sql.py)
  510. if __name__ == '__main__':
  511.     import sys
  512.     import config, gdebug
  513.     from initialize import locations, location_posters
  514.     from gconsole import check_args, check_args_with_db
  515.     
  516.     class Tmp:
  517.         def __init__(self):
  518.             self.debug = gdebug.GriffithDebug(True)
  519.     tmp = Tmp()
  520.     check_args(tmp)
  521.     locations(tmp)
  522.     tmp.config = config.Config(os.path.join(tmp.locations['home'], 'griffith.cfg'))
  523.     location_posters(tmp.locations, tmp.config)
  524.     
  525.     db = GriffithSQL(tmp.config, tmp.debug, tmp.locations['home'])
  526.     check_args_with_db(tmp)
  527.     
  528.     print '\nGriffithSQL test drive\n======================'
  529.     print "Engine: %s" % (db.metadata.engine.name)
  530.     print 'Database object name: db\n'
  531.  
  532. # vim: fdm=marker
  533.